
#include <string.h>

/*BSP*/
//#include "BSP_QR.h"
//#include "SYN6658.h"
#include "BSP_Sleep.h"

/*Driver*/
//#include "TTS.h"
//#include "Led.h"
//#include "WG.h"
//#include "Door.h"
//#include "Buzzer.h"
#include "RealTimeClock.h"
//#include "TTS_Storage.h"

/*Util*/
#include "util.h"
#include "fun_time.h"
#include "base64.h"
#include "MemAlloc.h"
#include "RC4Decode.h"
#include "Des.h"
#include "Contract.h"

/**/

//#include "Veriables.h"

//#include "Qr.h"
//#include "User.h"
//#include "QrInfo.h"
//#include "QrUser.h"
//#include "CasualUser.h"
//#include "FormalUser.h"
//#include "Qr_RD.h"
//#include "QrRadio.h"

#include "Env.h"
#include "Command.h"
#include "QrHN.h"
#include "Debug.h"

#define _QR_DBG	1
#define QR_DBG(...)	MDBG_PRINT(_QR_DBG, __VA_ARGS__)
#define QR_DBG_Buf(buf, len)	if(_QR_DBG)DBG_PRINT_BUF(buf, len)

#define MEM_EQ(s1, s2, n) (0 == memcmp(s1, s2, n))

 
typedef struct QRInofTag QRInfo_T;

typedef union {
	uint64_t num;
	char str[16];
}QrUid_T;

struct QRInofTag{
	uint8_t type;
	uint64_t UID;
	uint8_t DID[8];
	uint8_t useCount;
	int32_t stamp1;
	int32_t stamp2;	
};

typedef struct QRInofStrTag QRInfoStr_T;

struct QRInofStrTag{
	uint8_t type;
	char UID[64];
	uint8_t DID[8];
	uint8_t useCount;
	int32_t stamp1;
	int32_t stamp2;	
	uint8_t  second;
	uint8_t  Minute;
};


static inline void HN_Debug_QrInfo(QRInfoStr_T* qrInfo){
	QR_DBG("qrInfo->type = %c\n", qrInfo->type);
	QR_DBG("qrInfo->UID = %s\n", qrInfo->UID);
	QR_DBG("qrInfo->DID=");QR_DBG_Buf(qrInfo->DID, 4);QR_DBG("\n");
	QR_DBG("qrInfo->useCount = %u\n", qrInfo->useCount);
	QR_DBG("qrInfo->stamp1 = %u\n", qrInfo->stamp1);
	QR_DBG("qrInfo->stamp2 = %u\n", qrInfo->stamp2);
}

static int HN_Qr_Decode(uint8_t* cypt, uint8_t clen, uint8_t* plain, uint8_t* plen){
	int dlen = base64_decode((const unsigned char*)cypt, plain, clen);
	if (dlen < 0) {
		return -1;
	}
	QR_DBG("qrPwd=");QR_DBG_Buf(envData.qrPwd, envData.qrPwdLen);QR_DBG("\n");
	RC4_Decode(envData.qrPwd, envData.qrPwdLen, plain, dlen, plain);
	*plen = (uint8_t)dlen;
	return 0;
}

static const char* HN_Qr_PraserDID(const char* src, QRInfoStr_T* qrInfo){
	uint8_t i = 0;
	const char* s = src;
	uint64_t val;
	
	while(i < sizeof(qrInfo->DID) && *s != '|' && *s){
		//跳过分隔符','
		if(CharToValue(*s, 16) == 0xFF){
			s++;
			continue;
		}
		s = StrToVal_Dec(s, &val);
		qrInfo->DID[i++] = (uint8_t)val;
	}
	
	return s;
}

static const char* HN_Qr_PraserMap(const char* src, QRInfoStr_T* qrInfo){
	int ret = StrToArray_Hex((const uint8_t*)src, strlen(src), qrInfo->DID, sizeof(qrInfo->DID));
	return src + ret * 2;
}


static void HN_Qr_SetTime(struct tm_s *tm, uint8_t index, uint8_t val){
	switch(index){
	case 0: tm->tm_sec = val; break;
	case 1: tm->tm_min = val; break;
	case 2: tm->tm_hour = val; break;
	case 3: tm->tm_mday = val; break;
	case 4: tm->tm_mon = val; break;
	case 5: tm->tm_year = val + 2000; break;
	}
}

static void HN_Qr_SetupTime(struct tm_s *tm, uint8_t tbuf[], uint8_t len){
	uint8_t i = len;
	uint8_t index = 0;
	
	while(i > 0){
		--i;
		HN_Qr_SetTime(tm, index, tbuf[i]);
		++index;
	}
}

static const char* HN_Qr_PraserTime(const char* src, struct tm_s* current, int32_t *stamp){
	uint8_t tbuf[6];
	struct tm_s tmp;
	int ret = StrToArray_Dec((const uint8_t*)src, 12, tbuf, 6);
	if(ret < 3){
		return (const char*)0;
	}
	tmp = *current;
	HN_Qr_SetupTime(&tmp, tbuf, ret);
	*stamp = fun_mktime(&tmp);
	return src + ret * 2;
}

static const char* HN_Qr_Pro(const char* src, uint8_t *stamp){
	uint8_t tbuf[6];
	int ret = StrToArray_Dec((const uint8_t*)src, 2, tbuf, 1);
	if(ret < 1){
		return (const char*)0;
	}
	
	*stamp = tbuf[0];
	return src + ret * 2;
}

static int HN_Qr_Praser(uint8_t* qrBuf, uint8_t qrLen, struct tm_s* current, QRInfoStr_T* qrInfo){
	const char* s = (const char*)qrBuf;
	uint64_t val;
	uint8_t field = 0;
	qrInfo->type = 0;
	
	while(s&&*s){
		
		if(*s == '|'){
			//empty field
			field++;
			s++;
			continue;
		}
		
		switch(field){
		case 0:{
			qrInfo->type = *s;
		}
		break;
		
		case 1:{
			// praser UID
			uint32_t i = 0;
			
			 while(s&&*s&&i < sizeof(qrInfo->UID)-1){
				 if(*s == '|'){
					 break;
				 }
				 qrInfo->UID[i++] = *s;
				 ++s;
			 }		 
		}
		break;
		case 2:{
			// praser DID
			if(qrInfo->type < 'e'){
				s = HN_Qr_PraserDID(s, qrInfo);
			}
			else{
				s = HN_Qr_PraserMap(s, qrInfo);
			}
		}
		break;
		case 3:{
			// praser count
			s = StrToVal_Dec(s, &val);
			qrInfo->useCount = (uint8_t)val;
		}
		break;

		case 4:{
			// praser time stamp1
			s = HN_Qr_PraserTime(s, current, &qrInfo->stamp1);
		}
		break;

		case 5:{
			if(qrInfo->type == 'a'){
				s = HN_Qr_Pro(s, &qrInfo->second);
			}
			else{
				// praser time stamp2
				s = HN_Qr_PraserTime(s, current, &qrInfo->stamp2);
			}
		}
		
		break;
		case 6:{
			if(qrInfo->type == 'a'){
				s = HN_Qr_Pro(s, &qrInfo->Minute);
			}
		}
		break;
		
		default:
			return QR_ERR_INVALID;
		}
		//find field end
		while(s&&*s){
			if(*s == '|'){
				field++;
				s++;
				break;
			}
			++s;
		}
		
	}

	return 0;
}


static int HN_Qr_PreCheck(uint8_t* qrBuf){
	if(qrBuf[1] != '|'){
		return 0;
	}
	if('a' <= qrBuf[0] && qrBuf[0] <= 'h'){
		return 1;
	}
	return 0;
}


static int HN_Qr_CheckDoorMap(QRInfoStr_T* qrInfo, uint8_t did){
#if 0
	if(did > sizeof(qrInfo->DID) * 8 || did < 1){
		return 0;
	}

	return BitBuffer_read(qrInfo->DID, did - 1);
#else
	return 1;
#endif 
}

static int HN_Qr_CheckDoorNum(QRInfoStr_T* qrInfo, uint8_t did){
	uint32_t i;
	uint8_t notAllZero = 0;
	
	for(i = 0; i < sizeof(qrInfo->DID); i++){
		if(qrInfo->DID[i] == did){
			return 1;
		}
		if(qrInfo->DID[i] != 0){
			notAllZero = 1;
		}
	}
	//所有DID均为0，则不限定DID
	return notAllZero != 0 ? 0 : 1;
}

static int HN_Qr_CheckDID(QRInfoStr_T* qrInfo, uint8_t did){
	int ret;
	
	if(qrInfo->type < 'e'){
		ret = HN_Qr_CheckDoorNum(qrInfo, did);
	}
	else{
		ret = HN_Qr_CheckDoorMap(qrInfo, did);
	}
	return ret;
}



static int HN_Qr_CheckTime(QRInfoStr_T* qrInfo, uint32_t reference, uint8_t validity){
		
	if(qrInfo->stamp2 > 0){
		if((qrInfo->stamp1 <= reference) && (reference <= qrInfo->stamp2)){
			return 1;
		}
	}
	else{
		uint32_t timeDiff;
		//计算本地时间与二维码时间差
		if(reference > qrInfo->stamp1){
			timeDiff = (reference - qrInfo->stamp1);
		}
		else{
			timeDiff = (qrInfo->stamp1 - reference);			
		}
		
		if((qrInfo->second < timeDiff) && (timeDiff < (qrInfo->Minute*60))){
			//时间差过大且在合理范围内，则更新本地RTC
			RealTimeClock_SetTime(qrInfo->stamp1);
		}
		
		if(((reference - validity) <= qrInfo->stamp1) && (qrInfo->stamp1 <= (reference + validity))){
			return 1;
		}
	}
	return 0;
}


static int HN_Qr_Check(QRInfoStr_T* qrInfo, uint32_t reference, uint8_t validity){
	if(qrInfo->type == 'd' || qrInfo->type == 'h'){
	//d/h类，不限
		return 0;
	}
	if(!HN_Qr_CheckDID(qrInfo, envData.qrDID)){
		return QR_ERR_DID;
	}
	if(!HN_Qr_CheckTime(qrInfo, reference, validity)){
		return QR_ERR_TIME;
	}
	
	return 0;
}


static inline void HN_Qr_RecordDebug(HNQrRecord_T* record){
	QR_DBG("Qr Record:\n");
	QR_DBG("record->type=%c\n", record->type);
	QR_DBG("record->uid=%d\n", record->uid);
	QR_DBG("record->count=%d\n", record->count);
	QR_DBG("record->stamp1=%d\n", record->stamp1);
	QR_DBG("record->stamp2=%d\n", record->stamp2);
	QR_DBG("record->did=");QR_DBG_Buf(record->did, 6);QR_DBG("\n");
}

static uint8_t HN_Qr_Response(QRInfo_T* qrInfo, HNQrRecord_T* record){
	uint8_t qlen = sizeof(qrInfo->UID);
	//输出UID
	record->uid = qrInfo->UID;
	
	if(qrInfo->type > 'd'){
		//梯控二维码
		//输出DID
		if(envData.qrDidOut){
			memcpy(record->did, qrInfo->DID, 8);
			qlen += 8;
		}
	}
	else{
		//门禁二维码
	}
	record->type = qrInfo->type;
	record->count = qrInfo->useCount;
	record->stamp1 = qrInfo->stamp1;
	record->stamp2 = qrInfo->stamp2;
	return qlen;
}


static int HN_Qr_Process(uint8_t* qrBuf, uint8_t qrLen, uint8_t* out, uint8_t* olen){
	if(!HN_Qr_PreCheck(qrBuf)){
		return QR_ERR_INVALID;
	}
	struct tm_s current;
	QRInfoStr_T qrInfo;
	
	memset(&qrInfo, 0, sizeof(qrInfo));
	RealTimeClock_Get(&current);
	int ret = HN_Qr_Praser(qrBuf, qrLen, &current, &qrInfo);	
	HN_Debug_QrInfo(&qrInfo);
	if(ret){
		return ret;
	}
	uint32_t reference = fun_mktime(&current);
	ret = HN_Qr_Check(&qrInfo, reference, envData.qrValidity);
	if(ret){
		return ret;
	}
	*olen = strlen(qrInfo.UID);
	memcpy(out, qrInfo.UID, *olen);
	out[*olen] = 0;
	return ret;
}



//处理华诺二维
int procHNQr(unsigned char * buf, unsigned short len, unsigned char encript, uint8_t* out, uint8_t* olen){
	uint8_t qlen;
	int ret;

	if(len > 160){
		return QR_ERR_LEN;
	}
	
	uint8_t qr[128];
	//解码
	if(encript){
		ret = HN_Qr_Decode(buf, len, qr, &qlen);
		if(ret){		
			return QR_ERR_INVALID;
		}
	}
	else{
		qlen = len;
		memcpy(qr, buf, len);
	}

	//处理	
	qr[qlen++] = '\0';
	QR_DBG("Qr=%s\n", qr);
	ret = HN_Qr_Process(qr, qlen, out, olen);
	//响应
	return ret;
}

int Qr_ReceiveCommand(uint8_t* buf, uint8_t len){
	int ret;
	int dlen;
	uint8_t outData[128];
	XferFrame_T *frame = (XferFrame_T*)outData;
	
	dlen = base64_decode((const unsigned char*)buf, outData, len);
	if(dlen < 0){
		return QR_ERR_INVALID;
	}
	QR_DBG("QrCommand="); QR_DBG_Buf(outData, dlen); QR_DBG("\n");
	if((frame->stx != 0xAA) || !Command_Validate(outData, dlen)	){
		return QR_ERR_INVALID;
		
	}
	Env_Lock();
	ret = optProcess(frame->buffer, frame->length, 0);	
	Env_Unlock();
	if(ret < 0){
		return QR_ERR_FAIL;
	}
	
	return QR_S_CFG_OK;
}


int HN_Qr_Proc(uint8_t* buf, uint8_t len, uint8_t* out, uint8_t* olen){
	if(MEM_EQ(buf, "#*", 2)){
		return procHNQr(buf + 2, len - 2, 1, out, olen);
	}
	else
	if(MEM_EQ(buf, "-s", 2)){
		QR_DBG("Qr=%s\n", buf);
		return Qr_ReceiveCommand(buf + 2, len - 2);
	}
	else{
//			Qr_BuzzerPrompt(0);
	}
	return QR_ERR_TAG;
}


